/**
	Copyright (c) 2010 ATTi 
	All rights reserved.
	Author: Michael Shu
	Date: 8/11/2010
*/

public without sharing class OppForNatSalesHelperClass {
	private static Boolean isInsert = false;
	public static String errorMessage = 'Don\'t forget to enter this opportunity to your pipeline. Click ADD PRODUCT to continue.';
	private static String oppContractRecordTypeID;
	private static Set<ID> caseNATORecordTypeID;
	private static String CMR_Agency_Client_RT_NAME = 'CMR Agency Client';
	private static String GM   = 'GM';
	private static String NSM  = 'NSM';
	private static String ISM  = 'ISM';
	private static String EST  = 'EST';
	private static String EST_Manager = 'EST Manager';
	
	public static Set<ID> getCaseNATORecordTypeID(){
		if(caseNATORecordTypeID == null){
			caseNATORecordTypeID = new Set<ID>();
			for(String s : GeneralConstants.RT_NATL){
				ID temp = RecordTypeHelper.GetRecordTypeID('Case',  s);
				caseNATORecordTypeID.add(temp);
			}
		}
		return caseNATORecordTypeID;
	}	
	
	public static void setIsInsert(Boolean insertVal){
		isInsert = insertVal;
	} 
	
	public static Boolean getIsInsert(){
		return isInsert;
	} 

	public static ID getOppContractRecordTypeID(){
		if(oppContractRecordTypeID == null){
			oppContractRecordTypeID = RecordTypeHelper.GetRecordTypeID('Opportunity',  'Contract');	
		}
		return oppContractRecordTypeID;
	}
		
	public static void checkOppProduct(List<Opportunity> opps, Map<Id, Opportunity> oldOpps){ 
		Set<ID> oppIds = new Set<ID>();	
		List<Opportunity> opportunities = new List<Opportunity>();
		ID NaSaLOppRecordTypeID = getOppContractRecordTypeID();
		for(Opportunity o : opps){
			Opportunity oldOpp = oldOpps.get(o.Id);
			Boolean isError = o.RecordTypeId == NaSaLOppRecordTypeID && o.HasOpportunityLineItem == oldOpp.HasOpportunityLineItem && !o.HasOpportunityLineItem && o.Pricebook2Id == oldOpp.Pricebook2Id;
			if(isError){
				o.addError(OppForNatSalesHelperClass.errorMessage);
			}else if(!oldOpp.HasOpportunityLineItem && o.HasOpportunityLineItem){
				oppIds.add(o.Id);
				opportunities.add(o);
			}
		}
		if(!oppIds.isEmpty()){
			updateProductList(oppIds, opportunities, false);
		}
	}	
	
	public static void updateProductList (Set<ID> oppIds, List<Opportunity> opportunities, Boolean isDMLOpp){
		if(opportunities == null){
			opportunities = [select Product_List__c from Opportunity where Id IN: oppIds and HasOpportunityLineItem =: true];
		}
		List<OpportunityLineItem> oppItems = [select OpportunityId, PricebookEntry.Name from OpportunityLineItem where OpportunityId IN: oppIds Order by PricebookEntry.Name asc];
		Map<ID, String> oppItemMaps = new Map<ID, String>();
		for(OpportunityLineItem o : oppItems){
			String itemStr = '';
			if(oppItemMaps.containsKey(o.OpportunityId)){
				itemStr = oppItemMaps.get(o.OpportunityId);
			}
			itemStr +=  '"' + o.PricebookEntry.Name + '"';
			oppItemMaps.put(o.OpportunityId, itemStr);
		}
		for(Opportunity op : opportunities){
			op.Product_List__c = '';
			if(oppItemMaps.containsKey(op.Id)){
				op.Product_List__c = oppItemMaps.get(op.Id);
			}
		}
		if(isDMLOpp){
			try{
				update opportunities;
			}catch(Exception ex){
				GeneralConstants.mailAnyExceptionToMe('OppForNatSalesHelperClass', 'Update NatSales Opportunity from Product change fail', ex);
			}
		}		
	}
	
	public static void updateCasefieldsFromAccountTeams (List<Case> cases){
		Set<ID> acctids = new Set<ID>();
		for(Case c : cases){
			if(c.AccountId != null){
				acctids.add(c.AccountId);
			}
		}
		Map<ID, Account> accts = new Map<ID, Account>([select Id, (select AccountId, UserId, TeamMemberRole from AccountTeamMembers order by LastModifiedDate asc) 
		                                               from Account where RecordType.Name =: CMR_Agency_Client_RT_NAME and Id IN: acctids]);
	    for(Case c : cases){
	    	if(c.AccountId != null && accts.containsKey(c.AccountId)){
	    		List<AccountTeamMember> accteams = accts.get(c.AccountId).AccountTeamMembers;
	    		for(AccountTeamMember a : accteams){
	    			if(a.TeamMemberRole == GM){
	    				c.GM__c = a.UserId;
	    			}else if(a.TeamMemberRole == NSM){
	    				c.NSM__c = a.UserId;
	    			}else if(a.TeamMemberRole == ISM){
	    				c.ISM__c = a.UserId;
	    			}else if(a.TeamMemberRole == EST){
	    				c.EST__c = a.UserId;
	    			}else if(a.TeamMemberRole == EST_Manager){
	    				c.EST_Manager__c = a.UserId;
	    			}
	    		}
	    	}else{
		    	c.GM__c = null;
		    	c.NSM__c = null;
		    	c.ISM__c = null;
		    	c.EST__c = null;
		    	c.EST_Manager__c = null;	    		
	    	}
	    }
	}
	
	/*
	   created by plo, 11/11/2011, helper functions for contact trigger
	*/
	
	/*
	   help to collect Ids from a list of sObject that have record type with Id in the provided record type Ids
	*/
	public static List<sObject> collectionByRecordTypeIds(Set<Id> recordTypeIds, List<sObject> sObjList)
	{
		List<sObject> collectedObjs = new List<sObject>();
		
		if(!recordTypeIds.isEmpty() && !sObjList.isEmpty())
		{
			for(sObject obj : sObjList)
			{
				Id rtId = (Id)obj.get('RecordTypeId');
				if(rtId != null && recordTypeIds.contains(rtId))
				{
					collectedObjs.add(obj);
				}
			}
		}
		
		return collectedObjs;
	}
	
	/* 
	   AD-24884 
	   
	   Contacts shouldn't be saved (insert & update):
	   1. if the contact is an ATT Employee with record type "IOG Contact" 
	      - Contact Record Type is "IOG Contact" 
         - Email contains @att.com, @atti.com, @yellowpages.com, @attinteractive.com
		2. if the contact is duplicated and with record type "ATT Professional"
			- Contact Record Type is "ATT Professional" 
			- There is already one (or more) conatct with the same Email or ATTUID
		3. if the cotnact is record type "ATT Professional" and the associated account is a real customer
			- Contact recrod type is "ATT Professional" 
			- Field IOG_Customer_ID__c of the account trying to associate with is not blank
			
      All validations should be done in before trigger, error messages are:
      1. The email address provided indicates that this Contact is an AT&T Employee. You must create this contact with the "ATT Professional" record type 
      2. There already exists an ATT Professional Contact with this EMAIL or ATTuid. Please use the existing contact
      3. ATT Professional Contacts can not be associated with individual Customer Accounts. Please change the Account Name to either "ATT Professionals" (In-Region) or "Sales Professionals" (Out-Of-Region)
	*/
	public static final String IOG_CONTACT_WITH_ATTEMPLOYEE_EMAIL_MESSAGE = 'The email address provided indicates that this Contact is an AT&T Employee. You must create this contact with the "ATT Professional" record type';
	public static final String ATT_PROFESSIONAL_WITH_DUP_MESSAGE = 'There already exists an ATT Professional Contact with this EMAIL or ATTuid. Please use the existing contact';
	public static final String ATT_PROFESSIONAL_WITH_CUSTOMER_ACCOUNT_MESSAGE = 'ATT Professional Contacts can not be associated with individual Customer Accounts. Please change the Account Name to either "ATT Professionals" (In-Region) or "Sales Professionals" (Out-Of-Region)';
	public static final String CONTACT_RT_NAME_IOG_CONTACT = 'IOG Contact';
	public static final String CONTACT_RT_NAME_ATT_PROFESSIONAL = 'ATT Professional';
	
	public static final List<String> attEmployeeEmails = new List<String>{'@att.com', '@atti.com', '@yellowpages.com', '@attinteractive.com'};
	
	public static void triggerValidateIOGContacts()
	{
		if(trigger.isExecuting)
		{
			if(trigger.isbefore)
			{
				if(trigger.isInsert || trigger.isUpdate)
				{
			      List<Contact> filteredContact = (List<Contact>)OppForNatSalesHelperClass.collectionByRecordTypeIds(
		                                          new Set<Id>
		                                          {
		                                             RecordTypeHelper.GetRecordTypeID('Contact', 'IOG Contact'),
		                                             RecordTypeHelper.GetRecordTypeID('Contact', 'ATT Professional')
		                                          }, 
		                                          trigger.new);
		         
		         validateIOGContacts(filteredContact);
				}
			}
		}
	}
	
	public static void validateIOGContacts(List<Contact> cList)
	{
		Id rt_iog_contact = RecordTypeHelper.GetRecordTypeID('Contact', CONTACT_RT_NAME_IOG_CONTACT);
		Id rt_att_professinal = RecordTypeHelper.GetRecordTypeID('Contact', CONTACT_RT_NAME_ATT_PROFESSIONAL);
		
		List<Id> accntIdList = new List<Id>();
		for(Contact c : cList)
		{
			if(c.AccountId != null)
			   accntIdList.add(c.AccountId);
		}
		                          
		Map<Id,Account> assoAccntMap = new Map<Id,Account>(
		                              [SELECT Name, RecordTypeId, RecordType.Name, IOG_Customer_ID__c
		                               FROM Account WHERE Id IN :accntIdList]);
		
		// filtered list of Contacts that needs processing                      
		List<Contact> triggeredATTC = new List<Contact>();
		
		for(Contact c : cList)
		{
			// validate 1
		   if(c.RecordTypeId == rt_iog_contact)
		   {
		   	for(String e : attEmployeeEmails)
		   	{
		   		if(c.Email != null && c.Email.toLowerCase().contains(e))
		   		{
		   			c.addError(IOG_CONTACT_WITH_ATTEMPLOYEE_EMAIL_MESSAGE);
		   			break;
		   		}
		   	}
		   }
		   else if(c.RecordTypeId == rt_att_professinal) // validate 2 & 3
		   {
		   	Account a = assoAccntMap.get(c.AccountId);
		   	// validate 2, add to a list for later processing, so searching for dup contacts is a need-to-process based
		   	triggeredATTC.add(c);
		   	
		   	// validate 3
		   	if(a != null && a.IOG_Customer_ID__c != null)
		   	{
		   		c.addError(ATT_PROFESSIONAL_WITH_CUSTOMER_ACCOUNT_MESSAGE);
		   	}
		   }
		}
		
		// validate 2, search for dup ATT contacts
		if(!triggeredATTC.isEmpty())
		{
			/* collect Email and ATTUID, so we don't need to query everything */
			Set<String> emailAttuid = new Set<String>();
			for(Contact c : triggeredATTC)
			{
			   if(c.Email != null)
			      emailAttuid.add(c.Email);
			   
			   if(c.ATTUID__c != null)
			      emailAttuid.add(c.ATTUID__c);
			}
			
		   // get all ATT Professional contacts which may have the duplicated email or attuid, 
		   // use this list to search for duplicated contacts
		   Map<Id,Contact> attIOGC = new Map<Id,Contact>(
		                            [SELECT Email, ATTUID__c, RecordTypeId, RecordType.Name
		                             FROM Contact 
		                             WHERE RecordType.Name IN (:CONTACT_RT_NAME_ATT_PROFESSIONAL) 
		                             AND AccountId != null
		                             AND (Email IN :emailAttuid OR ATTUID__c IN :emailAttuid) 
		                             AND Id NOT IN :triggeredATTC]);
			
			for(Contact c : triggeredATTC)
			{
				// make sure current contact has a value for Email or ATTUID
				if(c.Email != null || c.ATTUID__c != null)
				{
					for(Contact allC : attIOGC.values())
					{
						// search for any contacts other than the current contact with the same Email or ATTUID (non-blank)
					   if(c.Id != allC.Id &&
					     (((c.Email != null && allC.Email != null) && (c.Email.toLowerCase() == allC.Email.toLowerCase())) || 
					      ((c.ATTUID__c != null && allC.ATTUID__c != null) && (c.ATTUID__c.toLowerCase() == allC.ATTUID__c.toLowerCase()))))
					   {
					      c.addError(ATT_PROFESSIONAL_WITH_DUP_MESSAGE);
					      break;
					   }
					}
				}
			}
		}
	}
	
	/* end */
}